/**
 * 类型推断
 * inference-compatibility
 */

let names = 'lison'
// names = 123  不能将字符串赋值给字符串类型

let arr5 = [1, "a"] // 自动识别为string&number类型数组
// arr5[0] = {} 不能赋值为其它类型

window.onmousedown = (event: MouseEvent) => {
    console.log(event)
    console.log(event.x)
    console.log(event.y)
}

interface IInfo {
    name: string
    info?: { age: number }
}
let iinfo: IInfo
const IInfo1 = { name: "1" }
const IInfo2 = { age: 18 }
const IInfo3 = { name: "3", age: 18 }
const IInfo4 = { name: "3", info: { age: 18 } }
const IInfo5 = { name: "3", info: { age: "18" } }
iinfo = IInfo1
// iinfo = IInfo2 不符合接口定义
iinfo = IInfo3
iinfo = IInfo4
// iinfo = IInfo5 // 会深层递归检测

/**
 * 函数兼容性检测
 */

let x = (a: number) => 0
let y = (b: number, c: string) => 0
// x = y // 报错 | 不能把形参多的函数赋值给函数少的参数
y = x

// 可选参数和剩余参数
const getSume = (arr: number[], callback: (...args: number[]) => number): number => {
    return callback(...arr)
}

let sum = getSume([1, 2, 3, 4], (...args: number[]): number => args.reduce((a, b) => a + b, 0))
let sum2 = getSume([1, 2, 3, 4], (arg1, arg2, arg3): number => arg1 + arg2 + arg3)
console.log(sum);
console.log(sum2);


// 函数参数双向协变 // 严格检测中可以开启或关闭该配置
// tslint:disable-next-line: no-empty
let funcA = (arg: number | string): void => { }
// tslint:disable-next-line: no-empty
let funcB = (arg: number): void => { }
// funcA = funcB // A不兼容B,因为A更宽松
funcB = funcA

// 返回值类型
let xx = (): string | number => 0
let yy = (): string => "0"
let zz = (): boolean => true

xx = yy
// yy = xx 报错
// yy = zz 报错


// 函数重载
function merge(arg1: number, age2: number): number
function merge(arg1: string, age2: string): string
function merge(arg1: any, arg2: any) {
    return arg1 + arg2
}

console.log(merge("1223", "3").length); // 编辑器内，鼠标放在merge方法上可以看到参数的类型


// 函数重载2 // sum2 方法没有string
function sum3(arg1: number, age2: number): number
function sum3(arg1: any, arg2: any) {
    return arg1 + arg2
}
let func = merge
func = merge
// func = sum3 // sum3没有string 类型 | 函数不兼容，报错

/**
 * 枚举
 */
enum StatusEnum {
    On,
    Off
}
enum AnimalEnum {
    Dog,
    Cat
}
let s = StatusEnum.On
s = 1
s = 4// 类型限定为number,虽然超出范围但是可以赋值
// s = AnimalEnum.Dog // 类型不兼容

// 字符串的情况
enum StatusEnum2 {
    On = "a",
    Off = "b"
}
let s2 = StatusEnum2.On
// s2 = "a" // 报错
// s2 = "0" // 报错
// s2 = 0 // 报错
s2 = StatusEnum2.On

/**
 * 类的兼容性
 */
class AnimalClass {
    public static age: number = 1
    constructor(public name: string) {
    }
}
class PeopleClass {
    public static age: string = "1"
    constructor(public name: string) { }
}
class FoodIsClass {
    constructor(public name: number) { }
}
let animal: AnimalClass = new AnimalClass("a")
let people: PeopleClass = new PeopleClass("a")
let food: FoodIsClass = new FoodIsClass(1)
animal = people // 兼容
// animal = food // 不兼容


// private protected属性的兼容性影响
class ParentClass {
    private age: number = 18
    constructor() { }
}
class ChildrenClass extends ParentClass {
    constructor() {
        super()
    }
}
class OtherClass {
    private age: number = 18
    constructor() { }
}
const children: ParentClass = new ChildrenClass()
// const other: ParentClass = new OtherClass() // 由于有私有属性或受保护的属性，会报错

// 泛型的兼容性
interface Data<T> { }
let data1: Data<number> = 1
let data2: Data<string> = "2"
data1 = data2

// 如果
interface Data2<T> {
    data: T
}
let data11: Data2<number> = { data: 1 }
let data22: Data2<string> = { data: "2" }
// data11 = data22 // 不兼容